<?php

namespace common\widgets;

use Closure;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

class Form extends \kartik\builder\Form
{

    /**
     * @const select控件
     */
    const SELECT2_WIDGET_CLASS = 'common\widgets\Select2';

    /**
     * @const 文件上传控件
     */
    const FILE_API_WIDGET_CLASS = 'common\widgets\FileApiWidget';

    /**
     * @var array
     */
    public $box = [];

    /**
     * 如果指定此项，则仅仅在特定场景显示
     *
     * @var array
     */
    public $on = [];

    /**
     * @var \yii\db\ActiveRecord | \yii\base\Model the model used for the form
     */
    public $model;

    /**
     * {@inheritdoc}
     */
    protected function renderFieldSet()
    {
        $content = '';
        $cols = (is_int($this->columns) && $this->columns >= 1) ? $this->columns : 1;
        $index = 0;


        if ($this->attributes)
        {
            foreach ($this->attributes as $attrName => $attrSetting)
            {
                if (isset($attrSetting['show']) && $attrSetting['show'])
                {
                    continue;
                }
                // 过滤无效字段
                if ( ! $this->model->isAttributeActive($attrName) && ! preg_match('/^@/', $attrName))
                {
                    unset($this->attributes[$attrName]);
                }
            }
        }

        if ($this->on)
        {
            if ( ! in_array($this->model->scenario, $this->on))
            {
                return "";
            }
        }

        $attrCount = count($this->attributes);
        $rows = (float) ($attrCount / $cols);
        $rows = ceil($rows);
        $names = array_keys($this->attributes);
        $values = array_values($this->attributes);
        $width = (int) (self::GRID_WIDTH / $cols);
        Html::addCssClass($this->rowOptions, 'row');
        $skip = ($attrCount == 1);
        for ($row = 1; $row <= $rows; $row++)
        {
            $content .= $this->beginTag('div', $this->rowOptions, $skip);
            for ($col = 1; $col <= $cols; $col++)
            {
                if ($index > ($attrCount - 1))
                {
                    break;
                }
                $attribute = $names[$index];
                if ($attribute == '@')
                {
                    $index++;
                    continue;
                }
                $settings = $values[$index];
                $settings = array_replace_recursive($this->attributeDefaults, $settings);
                $colOptions = ArrayHelper::getValue($settings, 'columnOptions', $this->columnOptions);
                $colWidth = $width;
                if (isset($colOptions['colspan']))
                {
                    $colWidth = $colWidth * (int) ($colOptions['colspan']);
                    unset($colOptions['colspan']);
                }
                $colWidth = (int) $colWidth;
                Html::addCssClass($colOptions, 'col-' . $this->columnSize . '-' . $colWidth);
                $content .= "\t" . $this->beginTag('div', $colOptions, $skip) . "\n";
                if ( ! empty($settings['attributes']))
                {
                    $this->raise(self::EVENT_BEFORE_RENDER_SUB_ATTR, $attribute, $index, ['settings' => &$settings]);
                    $content .= $this->renderSubAttributes($attribute, $settings, $index);
                    $this->raise(self::EVENT_AFTER_RENDER_SUB_ATTR, $attribute, $index, ['content' => &$content]);
                }
                else
                {
                    $this->raise(self::EVENT_BEFORE_PARSE_INPUT, $attribute, $index, ['settings' => &$settings]);
                    $content .= "\t\t" . $this->parseInput($attribute, $settings, $index) . "\n";
                    $this->raise(self::EVENT_AFTER_PARSE_INPUT, $attribute, $index, ['content' => &$content]);
                }
                $content .= "\t" . $this->endTag('div', $skip) . "\n";
                $index++;
            }
            $content .= $this->endTag('div', $skip) . "\n";
        }

        return $content;
    }

    /**
     * Parses the input markup based on type
     * 覆盖后增加特定字段可指定model
     *
     * @param string $attribute the model attribute
     * @param string $settings  the column settings
     * @param int    $index     the row index
     *
     * @return \kartik\form\ActiveField|mixed
     */
    protected function parseInput($attribute, $settings, $index)
    {
        $cModel = isset($settings['model']) ? $settings['model'] : $this->model;

        $type = ArrayHelper::getValue($settings, 'type', self::INPUT_TEXT);
        if ($this->staticOnly === true)
        {
            if (isset($this->form))
            {
                $this->form->staticOnly = true;
            }
            else
            {
                $settings['type'] = self::INPUT_STATIC;
            }
            if ($type !== self::INPUT_HIDDEN_STATIC)
            {
                $type = self::INPUT_STATIC;
            }
        }
        if (($type === self::INPUT_STATIC || $type === self::INPUT_HIDDEN_STATIC) && isset($settings['staticValue']))
        {
            $val = $settings['staticValue'];
            if ($val instanceof Closure)
            {
                $val = call_user_func($val, $this->hasModel() ? $cModel : $this->formName, $index, $this);
            }
            if ($this->hasModel())
            {
                $settings['fieldConfig']['staticValue'] = $val;
            }
            else
            {
                $settings['value'] = $val;
            }
        }
        else
        {
            $val = ArrayHelper::getValue($settings, 'value', null);
        }
        $val = ArrayHelper::getValue($settings, 'value', null);
        if ($type === self::INPUT_RAW)
        {
            if ($this->hasModel())
            {
                return $val instanceof Closure ? call_user_func($val, $cModel, $index, $this) : $val;
            }
            else
            {
                return $val instanceof Closure ? call_user_func($val, $this->formName, $index, $this) : $val;
            }
        }
        else
        {
            $hidden = '';

            if ($type === self::INPUT_HIDDEN_STATIC)
            {
                $settings['type'] = self::INPUT_STATIC;
                $options = ArrayHelper::getValue($settings, 'options', []);
                $hidden = $this->hasModel() ? Html::activeHiddenInput($cModel, $attribute, $options) :
                    Html::hiddenInput("{$this->formName}[{$attribute}]", $val, $options);
                $settings['options'] = ArrayHelper::getValue($settings, 'hiddenStaticOptions', []);
            }

            if ($type == self::INPUT_WIDGET)
            {
                //var_dump($settings);die();
            }

            $out = $this->hasModel() ?
                parent::renderRawActiveInput($this->form, $cModel, $attribute, $settings) :
                parent::renderRawInput("{$this->formName}[{$attribute}]", $settings);
            return $out . $hidden;
        }
    }
}